﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Health;
using SDS.SPHealthAnalyzerRules.Delegation.Helpers;

namespace SDS.SPHealthAnalyzerRules.Delegation.Rules
{
    /// <summary>
    /// Validates that SPN's exist for the C2WTS service account
    /// </summary>
    public class C2WTS_Has_SPNs : SPHealthAnalysisRule
    {
        private Guid CorrelationToken = Guid.NewGuid();

        private List<string> Errors = new List<string>();
        private List<string> Remedies = new List<string>();

        public override SPHealthCategory Category { get { return SPHealthCategory.Configuration; } }
        public override SPHealthCheckErrorLevel ErrorLevel { get { return SPHealthCheckErrorLevel.Error; } }

        public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
        {
            get
            {
                return new SPHealthAnalysisRuleAutomaticExecutionParameters()
                {
                    Schedule = SPHealthCheckSchedule.Daily,
                    Scope = SPHealthCheckScope.Any,
                    ServiceType = SPFarm.Local.Services.First(s => s.Name == "c2wts").GetType(),     // run on any server running C2WTS
                    RepairAutomatically = false
                };
            }
        }

        public override SPHealthCheckStatus Check()
        {
            SPHealthCheckStatus outval = SPHealthCheckStatus.Failed;

            LoggingService.Write(LoggingService.Category_C2WTS, TraceSeverity.Verbose, "Executing Health Check", CorrelationToken);

            // running as the system account
            Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(delegate { outval = doCheck(); });

            LoggingService.Write(
                LoggingService.Category_C2WTS,
                TraceSeverity.Verbose,
                String.Format("Health Check completed with outcome {0}", outval.ToString()),
                CorrelationToken);

            return outval;
        } // void Check()

        public override string Summary { get { return "DELEGATION: Service Principal Names (SPNs) not configured for Claims to Windows Token Service (C2WTS)"; } }
        public override string Explanation
        {
            get
            {
                return String.Format(
                    @"The following SPN errors were found:{0}{1}",

                    Environment.NewLine,
                    String.Join(Environment.NewLine, Errors.ToArray())
                    ).Trim();
            }
        }
        public override string Remedy
        {
            get
            {
                return String.Format(
                    @"{0}The following corrective actions are required:" +
                    @"{0}{1}",

                    Environment.NewLine,
                    String.Join(Environment.NewLine, Remedies.ToArray())
                    ).Trim();
            }
        }




        private SPHealthCheckStatus doCheck()
        {

            try
            {
                string SvcRunsAs_Raw = Helpers.Win32API.SvcConfigMgr.GetServiceAccount_W2CTS().Split('\\').Last();
                string SvcRunsAs = SvcRunsAs_Raw.ToLower() == "LocalSystem".ToLower()
                                 ? String.Format(@"{0}$", SPServer.Local.Name.ToUpper())
                                 : SvcRunsAs_Raw;

                var MatchingSPNs = Helpers.AD_SPN.Find(null, null, SvcRunsAs);
                var MatchingSPNs_Count = MatchingSPNs.Count();

                // if no SPNs
                if (MatchingSPNs_Count == 0)
                {
                    Errors.Add(String.Format("SPN was not defined for the C2WTS service account [{0}]", SvcRunsAs));
                    Remedies.Add(String.Format("Add an SPN for service account [{0}]", SvcRunsAs));
                }


            } // try
            catch (Exception ex)
            {
                LoggingService.Write(
                    LoggingService.Category_C2WTS,
                    TraceSeverity.High,
                    String.Format("Health Check encountered the following exception: {0}", ex.Message),
                    CorrelationToken);
            }


            // set return value
            return Errors.Count == 0
                   ? SPHealthCheckStatus.Passed
                   : SPHealthCheckStatus.Failed;

        } // doCheck()
    } // class

} // namespace
